package cn.faifai.tagapi.service.BackgroundServices.FileWatcher.impl;

import cn.faifai.framework.utils.fetcher.fileIdFetcher.FileIdFetcher;
import cn.faifai.framework.utils.fetcher.fileIdFetcher.FileIdFetcherFactory;
import cn.faifai.tagapi.entity.IFile;
import cn.faifai.tagapi.enums.PreDeleteStatus;
import cn.faifai.tagapi.repository.FileUrlRepository;
import cn.faifai.tagapi.service.BackgroundServices.FileWatcher.FileWatcherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
 * Windows 回收站行为：
 * 当用户删除文件，文件被收入回收站时，系统会生成两个文件，一个文件以$R开头，另一个文件以$I开头，
 * $R文件指向文件本身，$I指向文件的元数据（包括文件原路径，删除时间等等），查询$R文件id，文件id没有发生变化，
 * 这说明$R文件只是一个硬链接，所以可以通过文件id来判断文件是否被收入回收站。
 * 当发生文件被用户手动还原时，$R文件被删除，原路径的链接会被重新生成，但是$I文件不会被删除；当文件被手动永久删除时，$I文件也会被删除，
 * 无法确定这个还原行为是不是bug，回收站也没有相关开发文档，建议列为实验性功能，谨慎使用。
 * 最好是 todo 读取$I文件，利用$I文件记录的文件元数据来验证文件是否被还原，（但目前不知如何读取）也可通过命令行工具 fsutil hardlink list 文件路径获取所有硬链接来校验
 */
@Slf4j
@Service
public class WindowsRecycleBinFileWatcher implements FileWatcherService {

    @Autowired
    private FileUrlRepository fileUrlRepository;

    @Override
    public void afterModify(Path path) {
        log.info("modify: "+ path);
    }

    @Override
    public void afterCreate(Path path) {
        log.info("create: "+ path.getFileName());
        String fileName = path.getFileName().toString();
        if (this.isStartWith$I(fileName) || !this.isStartWith$R(fileName)) return;
        FileIdFetcher fileIdFetcher = FileIdFetcherFactory.getFileIdFetcher();
        try {
            String fileId = fileIdFetcher.getFileId(path.toString());
            IFile byOsFileId = fileUrlRepository.findByOsFileId(fileId);
            if (byOsFileId != null){
                byOsFileId.setPreDeleteStatus(PreDeleteStatus.IN_RECYCLE_BIN.getCode());
                byOsFileId.setRecycleBinFilePath(path.toAbsolutePath().toString());
                fileUrlRepository.save(byOsFileId);
            }
        } catch (IOException e) {
            log.info("获取文件id失败: {}",e.getMessage());
            throw new RuntimeException(e);
        }

    }

    @Override
    public void afterDelete(Path path) {
        log.info("Deleting: " + path);
        String fileName = path.getFileName().toString();

        if (!this.isStartWith$R(fileName) && !this.isStartWith$I(fileName)) {
            log.warn("Unsupported file type for deletion: " + fileName);
            return;
        }

        IFile byRecycleBinFilePath = null;
        if (this.isStartWith$R(fileName)) {
            byRecycleBinFilePath = fileUrlRepository.findByRecycleBinFilePath(path.toAbsolutePath().toString());
            if (byRecycleBinFilePath != null) {
                byRecycleBinFilePath.setPreDeleteStatus(PreDeleteStatus.SUSPECT_RESTORED.getCode());
            } else {
                log.warn("No record found for R-file in recycle bin: " + path);
                return;
            }
        } else if (this.isStartWith$I(fileName)) {
            String $RFileName = fileName.replace("$I", "$R");
            String $RFilePath = path.getParent().toString() + "\\" + $RFileName;
            byRecycleBinFilePath = fileUrlRepository.findByRecycleBinFilePath($RFilePath);
            if (byRecycleBinFilePath != null) {
                byRecycleBinFilePath.setPreDeleteStatus(PreDeleteStatus.SUSPECT_PERMANENTLY_DELETED.getCode());
            } else {
                log.error("No record found for I-file in recycle bin: " + $RFilePath);
                return;
            }
        }

        if (byRecycleBinFilePath != null) {
            fileUrlRepository.save(byRecycleBinFilePath);
        }
    }

    /**
     * 判断文件名是否以$R开头
     */
    public Boolean isStartWith$R(String fileName){
        return fileName.startsWith("$R");
    }


    /**
     * 判断文件名是否是$I开头
     */
    public Boolean isStartWith$I(String fileName){
        return fileName.startsWith("$I");
    }



    public static void main(String[] args) throws IOException {
//        \$ICDZMKE.txt
        Path path = Paths.get("D:\\$RECYCLE.BIN\\S-1-5-21-463390504-2282240019-982843704-1001");
//        Path path = Paths.get("D:\\tempmyself");
        new WindowsRecycleBinFileWatcher().start(path);
    }
}
